using System;
using System.Collections;
using SMS.SMPPClient.PDU;

namespace SMS.SMPPClient.PDU.Outgoing
{
    /// <summary>
    /// This class encapsulates common attributes for submit_sm and submit_multi PDUs.
    /// </summary>
    public abstract class MessageLCD2 : MessageLCD3
    {
        /// <summary>
        /// Limit of short message.
        /// </summary>
        public const int SHORT_MESSAGE_LIMIT = 160;
        protected byte _ProtocolID;
        private PriorityType _PriorityFlag;
        private string _ScheduleDeliveryTime;
        private string _ValidityPeriod;
        private bool _ReplaceIfPresentFlag;
        private byte _SMDefaultMessageID;
        private object _ShortMessage;

        /// <summary>
        /// Groups construction tasks for subclasses.
        /// </summary>
        /// <param name="protocolID">Protocol Identifier; network specific
        /// field.</param>
        /// <param name="priorityFlag">The priority level of the
        /// message.</param>
        /// <param name="scheduleDeliveryTime">Scheduled delivery time for the message
        /// delivery.  Set to null for immediate delivery.  Otherwise, use
        /// YYMMDDhhmmsstnn as the format.  See section 7.1.1 of the SMPP spec for more
        /// details.</param>
        /// <param name="validityPeriod">The validity period of this message.  Set to null
        /// to request the SMSC default validity period.  Otherwise, use YYMMDDhhmmsstnn
        /// as the format.  See section 7.1.1 of the SMPP spec for more details.</param>
        /// <param name="replaceIfPresentFlag">Flag indicating if submitted message should
        /// replace an existing message.</param>
        /// <param name="smDefaultMsgID">Allows use of a canned message from the SMSC.  If
        /// not using an SMSC canned message, set to 0.
        /// </param>
        /// <param name="shortMessage">The short message to send, up to 160
        /// octets.  If you need more length, use the MessagePayload
        /// property.  Do not use both at the same time!  Setting this to
        /// null will result in an empty string.  This can be either a string or a
        /// byte array; anything else will result in an exception.</param>
        /// <param name="serviceType">Indicates the SMS Application service associated with
        /// the message.  Set to null for the default SMSC settings.</param>
        /// <param name="esmClass">Indicates Message Mode and Message Type.  See the SMSC
        /// version 3.4 specification for details on setting this.  For most uses, you can
        /// set this to 0 (default SMSC actions).</param>
        /// <param name="registeredDelivery">The registered delivery type.</param>
        /// <param name="sourceAddrTON">The type of number of the source address.</param>
        /// <param name="sourceAddrNPI">The number plan indicator of the source
        /// address.</param>
        /// <param name="sourceAddress">The source address.</param>
        /// <param name="dataCoding">Defines the encoding scheme of the short message user
        /// data.</param>
        protected MessageLCD2(byte protocolID, PriorityType priorityFlag,
                            string scheduleDeliveryTime, string validityPeriod,
                            bool replaceIfPresentFlag, byte smDefaultMsgID,
                            object shortMessage, string serviceType, byte esmClass,
                            RegisteredDeliveryType registeredDelivery,
                            TONType sourceAddrTON, NPIType sourceAddrNPI,
                            string sourceAddress, DataCodingType dataCoding)
            :
                base(serviceType, esmClass,
                      registeredDelivery,
                      sourceAddrTON, sourceAddrNPI,
              sourceAddress, dataCoding)
        {
            _ProtocolID = protocolID;
            _PriorityFlag = priorityFlag;

            if (scheduleDeliveryTime != null)
            {
                if (scheduleDeliveryTime.Length == DELIVERY_TIME_LENGTH)
                    _ScheduleDeliveryTime = scheduleDeliveryTime;
                else
                    throw new ArgumentException(
                        "Scheduled delivery time not in correct format.");
            }
            else
                _ScheduleDeliveryTime = "";

            if (validityPeriod != null)
            {
                if (validityPeriod.Length == VALIDITY_PERIOD_LENGTH)
                    _ValidityPeriod = validityPeriod;
                else
                    throw new ArgumentException(
                        "Validity period not in correct format.");
            }
            else
                _ValidityPeriod = "";

            _ReplaceIfPresentFlag = replaceIfPresentFlag;
            _SMDefaultMessageID = smDefaultMsgID;
            _ShortMessage = shortMessage;

        }

        /// <summary>
        /// Creates the bytes after the destination address bytes.  This also inserts the TLV
        /// table data.  Common to both submit and submit multiple.
        /// </summary>
        /// <returns>The bytes in the PDU before the destination address(es).</returns>
        protected ArrayList GetBytesAfterDestination()
        {
            ArrayList pdu = new ArrayList();
            pdu.Add(_ESMClass);
            pdu.Add(_ProtocolID);
            pdu.Add((byte)_PriorityFlag);
            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_ScheduleDeliveryTime)));
            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_ValidityPeriod)));
            pdu.Add((byte)_RegisteredDelivery);

            if (_ReplaceIfPresentFlag == true)
                pdu.Add((byte)0x01);
            else
                pdu.Add((byte)0x00);

            pdu.Add((byte)_DataCoding);
            pdu.Add(_SMDefaultMessageID);

            byte[] msg;

            if (_ShortMessage == null)
                msg = new Byte[] { 0x00 };
            else if (_ShortMessage is string)
                msg =
                    System.Text.Encoding.ASCII.GetBytes((string)_ShortMessage);
            else if (_ShortMessage is byte[])
                msg = (byte[])_ShortMessage;
            else
                throw new ArgumentException(
                    "Short Message must be a string or byte array.");

            if (msg.Length >= MessageLCD2.SHORT_MESSAGE_LIMIT)
                throw new ArgumentException(
                    "Short message cannot be longer than " +
                    MessageLCD2.SHORT_MESSAGE_LIMIT + " octets.");

            pdu.Add((byte)msg.Length);
            pdu.AddRange(msg);

            pdu.TrimToSize();
            return pdu;
        }
    }
}
